package cn.stylefeng.guns.modular.gridsystem.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.guns.core.exception.ServiceException;
import cn.stylefeng.guns.core.factory.PageFactory;
import cn.stylefeng.guns.core.pojo.page.PageResult;
import cn.stylefeng.guns.modular.gridsystem.constants.ConfigSceneConstant;
import cn.stylefeng.guns.modular.gridsystem.entity.*;
import cn.stylefeng.guns.modular.gridsystem.enums.GatewaySceneExceptionEnum;
import cn.stylefeng.guns.modular.gridsystem.mapper.*;
import cn.stylefeng.guns.modular.gridsystem.model.param.GatewaySceneConfigParam;
import cn.stylefeng.guns.modular.gridsystem.model.param.GatewaySceneParam;
import cn.stylefeng.guns.modular.gridsystem.model.result.BizGatewayConfigTemplateResult;
import cn.stylefeng.guns.modular.gridsystem.model.result.GatewaySceneCfgResult;
import cn.stylefeng.guns.modular.gridsystem.service.GatewaySceneService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 网关场景表 服务实现类
 *
 * @author zxw
 * @date 2022/11/08 16:22
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GatewaySceneServiceImpl extends ServiceImpl<GatewaySceneMapper, GatewayScene> implements GatewaySceneService {

    private final GatewaySceneConfigMapper configMapper;

    private final BizGatewayConfigTemplateMapper configTemplateMapper;

    private final BizGatewayMapper gatewayMapper;

    private final BizGatewayConfigMapper gatewayConfigMapper;

    /**
     * 分页查询网关场景表
     * @param
     * @return
     */
    @Override
    public PageResult<GatewayScene> page() {
        // 构造条件
        LambdaQueryWrapper<GatewayScene> queryWrapper = new LambdaQueryWrapper<>();
        // 查询分页结果
        return new PageResult<>(this.page(PageFactory.defaultPage(), queryWrapper));
    }

    /**
     * 添加网关场景表
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(GatewaySceneParam param) {
        // 检查名称是否存在
        if (this.baseMapper.selectCount(new LambdaQueryWrapper<GatewayScene>().eq(GatewayScene::getSceneName, param.getSceneName())) > 0) {
            log.warn("相同名称的场景已存在,场景名称为：{}", param.getSceneName());
            throw new ServiceException(GatewaySceneExceptionEnum.SAME_NAME_EXISTED);
        }
        this.save(BeanUtil.toBean(param, GatewayScene.class));

    }

    /**
     * 删除网关场景表
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(GatewaySceneParam param) {
        this.queryAndValidScene(param);
        this.removeById(param.getId());
        // 删除子表数据
        configMapper.delete(new LambdaQueryWrapper<GatewaySceneConfig>().eq(GatewaySceneConfig::getSceneId, param.getId()));
    }

    /**
     * 编辑网关场景表
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(GatewaySceneParam param) {
        this.queryAndValidScene(param);
        // 检查名称是否存在
        if (this.baseMapper.selectCount(new LambdaQueryWrapper<GatewayScene>().ne(GatewayScene::getId, param.getId())
                .eq(GatewayScene::getSceneName, param.getSceneName())) > 0) {
            log.warn("相同名称的场景已存在,场景名称为：{}", param.getSceneName());
            throw new ServiceException(GatewaySceneExceptionEnum.SAME_NAME_EXISTED);
        }
        this.updateById(BeanUtil.toBean(param, GatewayScene.class));
    }

    /**
     * 编辑配置项
     * @param param 请求参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editConfig(GatewaySceneConfigParam param) {
        GatewaySceneConfig config = configMapper.selectById(param.getId());
        if (ObjectUtil.isEmpty(config)) {
            log.warn("网关配置不存在,配置主键为：{}", param.getId());
            throw new ServiceException(GatewaySceneExceptionEnum.CONFIG_NOT_EXISTED);
        }

        config.setDefaultValue(param.getDefaultValue());
        configMapper.updateById(config);
    }

    /**
     * 同步场景网关配置
     *
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncConfig(GatewaySceneParam param) {

        // 1、查询场景
        GatewayScene scene = this.queryAndValidScene(param);

        // 2、查询场景对应的所有配置
        List<GatewaySceneConfig> configList = configMapper.selectList(new LambdaQueryWrapper<GatewaySceneConfig>().eq(GatewaySceneConfig::getSceneId, scene.getId()));

        // 3、循环遍历场景对应的配置
        for (GatewaySceneConfig cfg : configList) {

            // 3.1、查询当前配置是否在网关配置当中存在
            if (gatewayConfigMapper.selectCount(new LambdaQueryWrapper<BizGatewayConfig>().eq(BizGatewayConfig::getGatewayConfigCode, cfg.getConfigCode())) > 0) {
                continue;
            }

            // 3.2、查询所有这个场景下关联的网关设备
            List<Integer> gatewayIds = gatewayMapper.selectList(new LambdaQueryWrapper<BizGateway>().eq(BizGateway::getSceneId, scene.getId()))
                    .stream()
                    .map(BizGateway::getId)
                    .collect(Collectors.toList());

            if (ObjectUtil.isNotEmpty(gatewayIds)) {
                for (Integer gatewayId : gatewayIds) {
                    BizGatewayConfig gatewayConfig = BizGatewayConfig.builder()
                            .gatewayId(gatewayId)
                            .gatewayConfigCode(cfg.getConfigCode())
                            .configValue(cfg.getDefaultValue())
                            .templateId(cfg.getConfigId())
                            .build();
                    // 保存数量
                    gatewayConfigMapper.insert(gatewayConfig);
                }
            }

        }

    }

    /**
     * 查看详情网关场景表
     *
     * @param param
     * @return
     */
    @Override
    public GatewayScene detail(GatewaySceneParam param) {
        return this.queryAndValidScene(param);
    }


    /**
     * 分页查询场景关联的配置模板
     *
     * @param param 查询参数
     * @return
     */
    @Override
    public PageResult<BizGatewayConfigTemplateResult> pageTemplate(GatewaySceneParam param) {
        return new PageResult<>(this.baseMapper.pageTemplate(PageFactory.defaultPage(), param));
    }

    /**
     * 添加配置模板
     *
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addTemplate(GatewaySceneParam param) {
        for (Long id : param.getTemplateIds()) {
            BizGatewayConfigTemplate template = configTemplateMapper.selectById(id);
            if (ObjectUtil.isEmpty(template)) {
                log.warn("网关配置模板不存在,配置模板主键为：{}", id);
                throw new ServiceException(GatewaySceneExceptionEnum.CONFIG_TEMPLATE_NOT_EXISTED);
            }
            GatewaySceneConfig config = GatewaySceneConfig.builder()
                    .sceneId(param.getId())
                    .configId(id)
                    .configCode(template.getCode())
                    .defaultValue(template.getDefaultValue())
                    .build();
            // 如果当前场景不存在配置模板，则写入数据，否则不进行写库操作
            if (configMapper.selectCount(new LambdaQueryWrapper<GatewaySceneConfig>()
                    .eq(GatewaySceneConfig::getSceneId, param.getId())
                    .eq(GatewaySceneConfig::getConfigId, id)) == 0) {
                configMapper.insert(config);
            }
        }

    }

    /**
     * 删除配置模板
     *
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTemplate(GatewaySceneParam param) {
        configMapper.deleteById(param.getTemplateId());
    }

    /**
     * 根据主键查询场景通用配置
     *
     * @param param 查询参数
     * @return
     */
    @Override
    public GatewaySceneCfgResult querySceneCfg(GatewaySceneParam param) {
        GatewaySceneCfgResult sceneCfgResult = GatewaySceneCfgResult.builder().build();
        GatewayScene scene = queryAndValidScene(param);
        // 查询并设置推荐通道数量
        GatewaySceneConfig channelCfg = configMapper.selectOne(new LambdaUpdateWrapper<GatewaySceneConfig>()
                .eq(GatewaySceneConfig::getConfigCode, ConfigSceneConstant.RECOMMEND_CHANNEL_NUM)
                .eq(GatewaySceneConfig::getSceneId, scene.getId()).last("limit 1"));
        if (ObjectUtil.isNotEmpty(channelCfg)) {
            sceneCfgResult.setRecommendChannelNum(channelCfg.getDefaultValue());
        }
        // 查询并设置推荐通道数量
        GatewaySceneConfig thresholdsCfg = configMapper.selectOne(new LambdaUpdateWrapper<GatewaySceneConfig>()
                .eq(GatewaySceneConfig::getConfigCode, ConfigSceneConstant.RECOMMEND_THRESHOLDS)
                .eq(GatewaySceneConfig::getSceneId, scene.getId()).last("limit 1"));
        if (ObjectUtil.isNotEmpty(thresholdsCfg)) {
            sceneCfgResult.setRecommendThresholds(thresholdsCfg.getDefaultValue());
        }
        return sceneCfgResult;
    }

    /**
     * 获取并校验网关场景
     *
     * @author zxw
     * @since 2022/11/08 16:22
     */
    private GatewayScene queryAndValidScene(GatewaySceneParam param) {
        GatewayScene gatewayScene = this.getById(param.getId());
        if (ObjectUtil.isEmpty(gatewayScene)) {
            log.warn("场景不存在,场景主键为：{}", param.getId());
            throw new ServiceException(GatewaySceneExceptionEnum.NOT_EXISTED);
        }
        return gatewayScene;
    }
}
